#-*-coding:utf-8-*-
import requests
#from urllib3 import NullHandler
import json 
import smtplib
from email.mime.text import MIMEText
from rich.table import Table
from rich.console import Console
import time
from playsound import playsound
#TODO
# 1.MAIL configure
# 2.sleep configure
# 3.reminder configure
# 4.mp3 player replace: Done 
# 5.pyinstaller test

def print_table(fr,to,sch_list):
    print('Current Spider Time:'+time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
    table = Table()
    table.add_column('NO.')
    table.add_column(f"[red]fromLocation:[yellow]{fr}")
    table.add_column(f"[blue]toLocation:[yellow]{to}")
    table.add_column(f"[green]vessel")
    cc=1
    for sch in sch_list:
        fr_info = sch['fromLocation']
        t1 = fr_info['date']+' '+fr_info['time']
        to_info = sch['toLocation']
        t2 = to_info['date']+' '+to_info['time']
        vs = sch['vessel']['name']
        table.add_row(str(cc),f'[red]{t1}',f'[blue]{t2}',f'[green]{vs}')
        cc +=1
    console = Console(record=True)
    console.print(table)
    
    return [table, console.export_html()]

def send_mail(html_text,config,v_c=1):

    subject = f"【船舶信息】有{v_c}条船可以预定了！"
    sender = config['sender']        #发送方
    password = config['passwd']
    
    recver = config['recver'].split(',')
    #recver = "zhukefeng@inspur.com,tongpeilin@inspur.com" #接收方
    #content = '共有{0}条船可预定\n'.format(ret.row_count)
    
    message = MIMEText(html_text,"html","utf-8")
    #html_text 发送表格     "html"表格格式   utf-8 编码格式
     
    message['Subject'] = subject #邮件标题
    message['To'] = ','.join(recver) #收件人
    message['From'] = sender #发件人
     
    try:
        #smtp = smtplib.SMTP_SSL("smtp.office365.com",587) #实例化smtp服务器
        smtp = smtplib.SMTP(config['server'],int(config['port'])) #实例化smtp服务器
        smtp.ehlo()
        smtp.starttls()
        smtp.login(sender,password)                 #发件人登录
        smtp.sendmail(sender,recver,message.as_string()) #as_string 对message的消息进行了封装
        smtp.close()
        print("发送货船信息到邮箱："+recver[0])
     
    except smtplib.SMTPException:
        print("Error: 无法发送邮件")

class Spy():
    def __init__(self):
        self.fr_name=''
        self.to_name=''
        self.frm = 's'
        self.dst = 'd'
        self.date = 'date'
        #self.url_code = "https://api.maersk.com/locations/?brand=maeu&type=city&pageSize=20&sort=cityName&cityName=Beihai&regionName=Guangxi&countryName=China"
        self.code_url = "https://api.maersk.com/locations/?brand=maeu&type=city&pageSize=100&sort=cityName&cityName="
        #self.url_info = f"https://api.maersk.com/oceanProducts/maeu/futureschedules?from=21N0QN82ONYIN&to=2IW9P6J7XAW72&containerIsoCode=42G1&fromServiceMode=CY&toServiceMode=CY&numberOfWeeks=4&dateType=D&date=2022-07-30&vesselFlag=&cargoType=DRY&containerType=DRY&containerLength=40&brandCode=maeu"
        self.info_url = ''
        self.city_data_file = 'city_code.pyt'
        #self.city_code = self.load_city_code(self.city_data_file)
        if not self.get_spy_info():
            exit(-1)
    
    def get_code(self,city_name):        
        rsp = requests.get(self.code_url+city_name).text.split('\n')
        sel = 0
        if(len(rsp) > 2):
            print("there are more than 1 cities start with ("+city_name+")")
            print("plz select:0,1,2,3...")
            while True:
                table = Table()
                table.add_column('Select NO.')
                table.add_column('[red]city full name')
                i = 0
                for rsp_sigle in rsp[:-1]:
                    if len(rsp_sigle) < 10:
                        break
                    code_info = json.loads(rsp_sigle)
                    table.add_row(f'{i}',f"[red]{code_info['cityName']}")
                    i +=1
                console = Console()
                console.print(table)
                sel = int(input('which one(0,1,2,3..) do U select: '))
                if isinstance(sel,int) :
                    break
                print('input error')
        else:
            if(len(rsp) == 2):
                sel = 0
            else:
                print("there is no city name start with ("+city_name+")")
                exit(-1)
        sel_city = json.loads(rsp[sel])
        ret = [sel_city['cityName'],sel_city['maerskGeoLocationId']]
        print(f"cityName: {ret[0]}, cityCode: {ret[1]}")
        return ret
    
    def get_info_url(self):
        self.info_url = f"https://api.maersk.com/oceanProducts/maeu/futureschedules?from={self.frm}&to={self.dst}&containerIsoCode=42G1&fromServiceMode=CY&toServiceMode=CY&numberOfWeeks=4&dateType=D&date={self.date}&vesselFlag=&cargoType=DRY&containerType=DRY&containerLength=40&brandCode=maeu"
    
    def get_spy_info(self):
        #handle source,destination and date information
        print('plz input source,destination,date')
        frm = input("\nFrom(city name): ")
        self.fr_name,self.frm = self.get_code(frm)
        
        dst = input('\ndestination(city name): ')
        self.to_name,self.dst = self.get_code(dst)
        day = time.localtime(time.time()+24*60*60) #add 1 day:24*60*60
        tomorrow = time.strftime('%Y-%m-%d', day)
        self.date = input(f'\nstart date (format:2022-07-30), default Tomorrow({tomorrow}): ')
        if self.date == '':
            self.date=tomorrow
            print(f'date input is None, set default date:{self.date}')
        import re
        if not re.match('([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8])))', self.date):
            print("date input error(yyyy-mm-dd)")
            return False 
        self.get_info_url() 
        return True
    
    def parse_rsp(self,rsp):
        order_info = json.loads(rsp)
        print("\n##########################################################################")
        print(f'Getting Schedules List From:{self.date}')
        if(len(order_info['products'])>0):
            ret = print_table(self.fr_name, self.to_name, order_info['products'][0]['schedules'])
            self.html_text = ret[1]
            return ret[0]
        else:
            print(f'no vessel from {self.fr_name} to {self.to_name} after {self.date} at '+ time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
            print("-----------------------------------------------------------------------------\n")
            return Table()    
    def search(self,config):
        #step 0: get response of from/to/date url requests
        rsp = requests.get(self.info_url)
        
        #step 1: parse the response 
        ret = self.parse_rsp(rsp.text)

        #step 2: if not None, send mail to notify
        if(ret.row_count>0):
            if config['mail']['enable']  == 'yes':
                send_mail(self.html_text,  config['mail'],ret.row_count)
            if config['reminder']['enable'] == 'yes':
                r_config = config['reminder']
                if(r_config['beep'] == 'yes'):
                    import winsound                
                    winsound.Beep(32767,1000*int(r_config['beeptime']))
                time.sleep(1)
                if(r_config['mp3'] == 'yes'):
                    playsound(r_config['mp3name']) 
def run(t):
    #Input module
    #input source and destination, date, information.
    import os
    if os.path.exists('config.cfg'):
        from configparser import ConfigParser
        config_parse = ConfigParser()
        config_parse.read('config.cfg')
    else:
        print('there is no config file: config.cfg, select default config')
        config_parse = dict()
        config_parse['mail']=dict()
        config_parse['reminder']=dict()
        config_parse['sleep']=dict()
        config_parse['mail']['enable']='no'
        config_parse['reminder']['enable']='no'
        config_parse['sleep']['time']=t
    b_spy = Spy()
    print('\nspider ready\n')
    while True:
        ret = b_spy.search(config_parse)
        t=int(config_parse['sleep']['time'])
        time.sleep(t)
    
if __name__ == "__main__":
    # 600 equals 600 seconds
    run(60)